package com.loveprogrammer.eternity.model.map;

import com.loveprogrammer.eternity.action.BaseAction;
import com.loveprogrammer.eternity.action.Battle;
import com.loveprogrammer.eternity.common.Constants;
import com.loveprogrammer.eternity.factory.MapFactory;
import com.loveprogrammer.eternity.factory.NPCFactory;
import com.loveprogrammer.eternity.factory.template.MapTemplate;
import com.loveprogrammer.eternity.model.Character;
import com.loveprogrammer.eternity.model.Hero;
import com.loveprogrammer.eternity.model.Monster;
import com.loveprogrammer.eternity.model.console.ConsolePrint;
import com.loveprogrammer.eternity.model.game.HeroWrapper;
import com.loveprogrammer.eternity.model.npc.NPC;
import com.loveprogrammer.eternity.model.product.FallingCoinCalculator;
import com.loveprogrammer.eternity.model.product.FallingGoodsCalculator;
import com.loveprogrammer.eternity.utils.BeanCopyUtils;
import io.netty.util.HashedWheelTimer;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @version 1.0.0
 * @description: 地图
 * @author: eric
 * @date: 2022-08-03 11:05
 **/
public class Map extends BaseAction {

    private String id;

    private FindMonstersEngine findMonsterEngine;

    // 级别 1 就是 0-9级  9 就是 90-99级
    private int level;

    private int floorId;

    private List<MapTemplate.FloorMap> floorMaps;

    private String name;

    private String desc;

    private String teamSize;

    // 可能出现的野怪
    private List<MonsterInMap> monsters;

    // NPC列表
    private List<NPC> npcList;

    // 关底boss
    private List<MapTemplate.BossData> bossList;

    public Map(FindMonstersEngine findMonstersEngine, int level, String name,
               String desc, String teamSize, List<MonsterInMap> monsters,
               List<NPC> npcList, List<MapTemplate.BossData> bossList, List<MapTemplate.FloorMap> floorMaps) {
        if(findMonstersEngine == null){
            findMonstersEngine = new DefaultFindMonsters();
        }
        this.findMonsterEngine = findMonstersEngine;
        this.level = level;
        this.name = name;
        this.monsters = monsters;
        this.desc = desc;
        this.teamSize = teamSize;
        this.npcList = npcList;
        this.bossList = bossList;
        this.floorMaps = floorMaps;
    }

    public Map(MapTemplate mapTemplate) {
        this.findMonsterEngine = new DefaultFindMonsters();
        if(mapTemplate.getId().equals("1")){
            this.findMonsterEngine = new FirstMapFindMonsters();
        }
        this.name = mapTemplate.getName();
        this.level = mapTemplate.getLevel();
        this.monsters = MapFactory.createMonsters(mapTemplate);
        this.desc = mapTemplate.getDesc();
        this.teamSize = mapTemplate.getTeamSize();
        this.npcList = NPCFactory.batchAddNPC(mapTemplate.getNpcIds());
        this.bossList = mapTemplate.getBossList();
        this.floorMaps = mapTemplate.getFloors();
        this.id = mapTemplate.getId();
    }

    // 特殊场所
    public void fight(HeroWrapper heroWrapper, ScheduledExecutorService executorService,
                      ScheduledExecutorService subFightExecutorService) throws Exception {
        Hero hero = heroWrapper.getHero();
        List<Monster> fightPets = heroWrapper.getFightPets();
        List<Character> attacks = new ArrayList<>();
        attacks.add(hero);
        attacks.addAll(fightPets);

        List<Monster> monsters = findMonsterEngine.findMonsters(heroWrapper, this);

        Battle battle = new Battle(executorService, subFightExecutorService);
        battle.setFallingGoodsCalculator(new FallingGoodsCalculator());
        battle.setFallCoinCalculator(new FallingCoinCalculator());
        battle.setCampA(BeanCopyUtils.deepCopy(attacks));
        battle.setAttackHero(heroWrapper);
        ConsolePrint.publishMessage("发起进攻方",1);
        for (Character character : battle.getCampA()) {
            System.out.println(character.toString());
        }

        battle.setCampB(monsters);
        ConsolePrint.publishMessage("怪物群",2);
        for (Character character : battle.getCampB()) {
            ConsolePrint.publishMessage(character.toString(),2);
        }
        CompletableFuture<?> future = null;
        Boolean result = false;
        try {
            future = CompletableFuture.supplyAsync(battle::fight);

            // 5分钟 300秒
            result = (Boolean) future.get(Constants.TIME_OF_EACH_ROUND, TimeUnit.SECONDS);
        } catch (Exception e) {
            // e.printStackTrace();
            if(future != null && !future.isCancelled()) {
                future.cancel(true);
            }
            ConsolePrint.publishMessage("5分钟超时或者发生异常，平手", 1);
            return;
        }

        ConsolePrint.publishMessage(result ? "挑战成功" : "失败了，继续挑战", 1);

    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<MonsterInMap> getMonsters() {
        return monsters;
    }

    public void setMonsters(List<MonsterInMap> monsters) {
        this.monsters = monsters;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public String getTeamSize() {
        return teamSize;
    }

    public void setTeamSize(String teamSize) {
        this.teamSize = teamSize;
    }

    public List<NPC> getNpcList() {
        return npcList;
    }

    public void setNpcList(List<NPC> npcList) {
        this.npcList = npcList;
    }

    public List<MapTemplate.BossData> getBossList() {
        return bossList;
    }

    public void setBossList(List<MapTemplate.BossData> bossList) {
        this.bossList = bossList;
    }

    public int getFloorId() {
        return floorId;
    }

    public void setFloorId(int floorId) {
        this.floorId = floorId;
    }

    public List<MapTemplate.FloorMap> getFloorMaps() {
        return floorMaps;
    }

    public void setFloorMaps(List<MapTemplate.FloorMap> floorMaps) {
        this.floorMaps = floorMaps;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
